package can.bishe.common.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import javax.annotation.PostConstruct;

import can.bishe.modules.senic.entity.SenicInfoEntity;
import can.bishe.modules.senic.entity.SenicScoresEntity;
import can.bishe.modules.senic.service.SenicScoresService;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class CoreAlgorithm {
	
	@Autowired
	private SenicScoresService senicScoresService;
	@Autowired
	private static SenicScoresService staticsenicScoresService;
	
    @PostConstruct
    public void init() {
        staticsenicScoresService = senicScoresService;
	}

	// 喜爱基数  评分大于喜爱基数的 评价定义为喜欢
	public static final Double loveabase = 4.5;
	
	public static Integer userIndex = 4;
	// 组装用户x景点矩阵
	public List<Long> getUserToSenicModel(List<Long> userLoveList){
		
		Map<Integer,List> resMap = new HashMap<>();

//		List<Long> userList = staticsenicScoresService.getUserList(); //用户数组
//		List<Long> senicList = staticsenicScoresService.getSenicList(); // 景点数组
//		// 用户-景区 喜爱列表 item
//		for(Long userId:userList){
//			List<Long> userlovelist = staticsenicScoresService.getUserLoveList(userId.longValue());
//			resMap.put(userId.intValue(), userlovelist);
//		}

		Double rk = 0D;
		Integer rUser = 0; //相关用户id
		List<Long> rList = new ArrayList<>();
		//相似度计算
		for(Map.Entry<Integer,List> entryOne:resMap.entrySet()){
			Integer mapKeyOne = entryOne.getKey();
			List<Long> mapValueOne = entryOne.getValue();
			for(Map.Entry<Integer,List> entryTwo:resMap.entrySet()){
				Integer mapKeyTwo = entryTwo.getKey();
				List<Long> mapValueTwo = entryTwo.getValue();
				Double rks =  this.getRelate(mapValueOne, mapValueTwo);
				if(rks == null) return null;
				if(rks > rk) { //越大关联度越高
					rUser = mapKeyTwo;
					rList = mapValueTwo;
				}else {
					rUser = mapKeyOne;
					rList = mapValueOne;
				}
			}
		}
		// 合并去重
		rList.addAll(userLoveList);
		List<Long> favoList = delRepeat(rList);
		return favoList;

	}   

	public static Double getRelate(List<Long> xs, List<Long>  ys){
		try{
	        int n=xs.size();
	        double Ex= xs.stream().mapToDouble(x->x).sum();
	        double Ey=ys.stream().mapToDouble(y->y).sum();
	        double Ex2=xs.stream().mapToDouble(x->Math.pow(x,2)).sum();
	        double Ey2=ys.stream().mapToDouble(y->Math.pow(y,2)).sum();
	        double Exy= IntStream.range(0,n).mapToDouble(i->xs.get(i)*ys.get(i)).sum();
	        double numerator=Exy-Ex*Ey/n;
	        double denominator=Math.sqrt((Ex2-Math.pow(Ex,2)/n)*(Ey2-Math.pow(Ey,2)/n));
	        if (denominator==0) return 0.0;
	        return numerator/denominator;
		}catch(IndexOutOfBoundsException e) {
			e.getMessage();
		}
		return null;
    }
	
	public static List<Long> delRepeat(List<Long> list) {
	     List<Long> myList = list.stream().distinct().collect(Collectors.toList());
		 return myList ;
	}

	public List<Long> getSenicUserModel2(Long userId){
		// 全部用户
		List<Long> userList = senicScoresService.getUserList();
		Map<Long,List<Long>> scoreX = new HashMap<>();
		for(Long ids:userList) {
			List<Long> userScoresSenic = senicScoresService.getSenicList(ids);
			if(userScoresSenic.size()!=0) {
				scoreX.put(ids, userScoresSenic);
			}else {
				scoreX.put(ids, userScoresSenic);
			}
		}
		//当前用户的评价历史
		List<Long> userIdx = scoreX.get(userId);
		//构建矩阵
		Map<Long,List<Long>> matrix = new HashMap<>();
		if(userIdx.size()!=0) {
			for(Map.Entry<Long, List<Long>> entryX:scoreX.entrySet()) {
				List<Long> matrixOneList = new ArrayList<>();
				for(Map.Entry<Long, List<Long>> entryY:scoreX.entrySet()) {
					if(entryX.getKey().equals(entryY.getKey())) {
						matrixOneList.add(0L);
					}else {
						for(Long senicOne:entryX.getValue()) {
							Long sameFlag = 0L;
							for(Long senicTwo:entryX.getValue()) {
								if(senicOne.equals(senicTwo)) {
									sameFlag += 1;
								}
							}
							matrixOneList.add(sameFlag);
						}
					}
				}
				matrix.put(entryX.getKey(), matrixOneList);
			}
		}
		// 计算相似度
		Map<Long,List<Double>> matrixTwo = new HashMap<>();
		for(Map.Entry<Long, List<Long>> userModelOne:matrix.entrySet()) {
			List<Long> binji = new ArrayList<>();
			if(userModelOne.getKey() == userId) {
				continue;
			}
			List<Long> userIdy = userModelOne.getValue();
			binji.addAll(userIdx);
			binji.addAll(userIdy);
			// 去重求并集
			HashSet<Long> set = new HashSet(binji);
			binji.clear();
			binji.addAll(set);
			List<Double> tx = new ArrayList<>();
			int fenmu = binji.size();
			for(Long x:userIdy) {
				Double res = (double) (x/fenmu);
				tx.add(res);
			}
			matrixTwo.put(userModelOne.getKey(),tx);
		}
		
		// 获取相似度列表
		List<Double> similerList = matrixTwo.get(userId);
		
		try {
			userIndex = similerList.indexOf(Collections.max(similerList));
		}catch(NullPointerException e) {
			System.out.println(e.getMessage());
		}
		// 获取最相近的用户 一个也可以是一组取排名
		Long resUserId = userList.get(userIndex);
		List<Long> resUserLoveList = senicScoresService.getSenicList(resUserId);
		Iterator it = resUserLoveList.iterator();
		// 并集-交集 
		while(it.hasNext()) {
			for(Long ne_no:userIdx) {
				if(it.next().equals(ne_no)) {
					it.remove();
				}
			}
		}
		for(Long re_no:resUserLoveList) {
			System.out.println("喜欢的景区"+re_no);
		}
		return resUserLoveList;
	}
	
	public List<Integer> getSenicUserModel3(Long userId) {
		// 我的喜爱列表
		EntityWrapper ew1 = new EntityWrapper<SenicScoresEntity>();
		ew1.eq("user_id",userId);
		ew1.setSqlSelect("senic_id");
		ew1.gt("senic_score","4.0");
		List<SenicScoresEntity> myloveEntityList = senicScoresService.selectList(ew1);
		List<Integer> myloveList = new ArrayList<>();
		for(SenicScoresEntity ssOne : myloveEntityList){
			myloveList.add(ssOne.getSenicId());
		}
		// 与我有交集的用户列表
		EntityWrapper ew2 = new EntityWrapper<SenicScoresEntity>();
		ew2.setSqlSelect("user_id");
		ew2.ne("user_id",userId);
		ew2.in("senic_id",myloveList);
		List<SenicScoresEntity> commonEntityUser = senicScoresService.selectList(ew2);
		List<Integer> commonUser = new ArrayList<>();
		for(SenicScoresEntity ssOne : commonEntityUser){
			commonUser.add(ssOne.getUserId());
		}
		// 他们喜欢的景点列表
		Map<Integer,List<Integer>> otherLoveOneCol = new HashMap<>();
		for(Integer otherUserId:commonUser){
			EntityWrapper ew3 = new EntityWrapper<SenicScoresEntity>();
			ew3.eq("user_id",otherUserId);
			ew3.setSqlSelect("senic_id");
			ew3.gt("senic_score","4.0");
			List<SenicScoresEntity> otherloveEntityList = senicScoresService.selectList(ew3);
			List<Integer> otherloveList = new ArrayList<>();
			for(SenicScoresEntity ssOne : otherloveEntityList){
				otherloveList.add(ssOne.getSenicId());
			}
			otherLoveOneCol.put(otherUserId,otherloveList);
		}
		// 求交并系数
		Map<Integer,Double> similarOneCol = new HashMap<>();
		for(Map.Entry<Integer,List<Integer>> entry:otherLoveOneCol.entrySet()){
			List<Integer> otherUserlikeList = entry.getValue();
			Double similarNum = this.MergerNum(myloveList,otherUserlikeList).doubleValue();
			similarOneCol.put(entry.getKey(),similarNum);
		}
		// 取相似度最高的k个用户喜爱列表 k = 1
		Integer otherId = 4;
		Double  alikeNum = 0D;
		Double xisu;
		for(Map.Entry<Integer,Double> entrys: similarOneCol.entrySet()){
			xisu = entrys.getValue();
			if(xisu > alikeNum) {
				otherId = entrys.getKey();
				alikeNum = xisu;
			}
		}
		List<Integer> helikeIdList = otherLoveOneCol.get(otherId);
		if(helikeIdList != null){
			helikeIdList.removeAll(myloveList);
		}
		if(helikeIdList != null){
			return helikeIdList;
		}
		List<Integer> defualtList = new ArrayList<Integer>();
		defualtList.add(4);
		return defualtList;
	}

	public BigDecimal MergerNum(List<Integer> mylist,List<Integer> otherlist){
		// 交集
		List<Integer> intarget = new ArrayList<>(otherlist);
		intarget.retainAll(mylist);
		// 并集
		List<Integer> outarget = new ArrayList<>(otherlist);
		outarget.removeAll(mylist);
		outarget.addAll(mylist);
		int fenzi = intarget.size();
		int fenmu = outarget.size();
		if (fenmu == 0) {
			fenmu = 1; // defualt 1
		}
		BigDecimal fenziB = new BigDecimal(fenzi);
		BigDecimal fenmuB = new BigDecimal(fenmu);
		BigDecimal res = fenziB.divide(fenmuB,2, RoundingMode.HALF_UP);
		return res;
	};
}
